﻿namespace FastColoredTextBoxNS
{
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;

    public partial class Ruler : UserControl
    {
        public EventHandler TargetChanged;

        [DefaultValue(typeof(Color), "ControlLight")]
        public Color BackColor2 { get; set; }

        [DefaultValue(typeof(Color), "DarkGray")]
        public Color TickColor { get; set; }

        [DefaultValue(typeof(Color), "Black")]
        public Color CaretTickColor { get; set; }

        private FastColoredTextBox target;

        [Description("Target FastColoredTextBox")]
        public FastColoredTextBox Target
        {
            get
            {
                return this.target;
            }
            set
            {
                if (this.target != null)
                {
                    this.UnSubscribe(this.target);
                }
                this.target = value;
                this.Subscribe(this.target);
                this.OnTargetChanged();
            }
        }

        public Ruler()
        {
            this.InitializeComponent();

            this.SetStyle(
                ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
            this.MinimumSize = new Size(0, 24);
            this.MaximumSize = new Size(int.MaxValue / 2, 24);

            this.BackColor2 = SystemColors.ControlLight;
            this.TickColor = Color.DarkGray;
            this.CaretTickColor = Color.Black;
        }

        protected virtual void OnTargetChanged()
        {
            if (this.TargetChanged != null)
            {
                this.TargetChanged(this, EventArgs.Empty);
            }
        }

        protected virtual void UnSubscribe(FastColoredTextBox target)
        {
            target.Scroll -= this.target_Scroll;
            target.SelectionChanged -= this.target_SelectionChanged;
            target.VisibleRangeChanged -= this.target_VisibleRangeChanged;
        }

        protected virtual void Subscribe(FastColoredTextBox target)
        {
            target.Scroll += this.target_Scroll;
            target.SelectionChanged += this.target_SelectionChanged;
            target.VisibleRangeChanged += this.target_VisibleRangeChanged;
        }

        private void target_VisibleRangeChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        private void target_SelectionChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        protected virtual void target_Scroll(object sender, ScrollEventArgs e)
        {
            this.Invalidate();
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (this.target == null)
            {
                return;
            }

            Point car =
                this.PointToClient(this.target.PointToScreen(this.target.PlaceToPoint(this.target.Selection.Start)));

            Size fontSize = TextRenderer.MeasureText("W", this.Font);

            int column = 0;
            e.Graphics.FillRectangle(
                new LinearGradientBrush(
                    new Rectangle(0, 0, this.Width, this.Height), this.BackColor, this.BackColor2, 270),
                new Rectangle(0, 0, this.Width, this.Height));

            float columnWidth = this.target.CharWidth;
            var sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Near;

            Point zeroPoint = this.target.PositionToPoint(0);
            zeroPoint = this.PointToClient(this.target.PointToScreen(zeroPoint));

            using (var pen = new Pen(this.TickColor))
            using (var textBrush = new SolidBrush(this.ForeColor))
                for (float x = zeroPoint.X; x < this.Right; x += columnWidth, ++column)
                {
                    if (column % 10 == 0)
                    {
                        e.Graphics.DrawString(column.ToString(), this.Font, textBrush, x, 0f, sf);
                    }

                    e.Graphics.DrawLine(
                        pen, (int)x, fontSize.Height + (column % 5 == 0 ? 1 : 3), (int)x, this.Height - 4);
                }

            using (var pen = new Pen(this.TickColor)) e.Graphics.DrawLine(pen, new Point(car.X - 3, this.Height - 3), new Point(car.X + 3, this.Height - 3));

            using (var pen = new Pen(this.CaretTickColor))
            {
                e.Graphics.DrawLine(
                    pen, new Point(car.X - 2, fontSize.Height + 3), new Point(car.X - 2, this.Height - 4));
                e.Graphics.DrawLine(pen, new Point(car.X, fontSize.Height + 1), new Point(car.X, this.Height - 4));
                e.Graphics.DrawLine(
                    pen, new Point(car.X + 2, fontSize.Height + 3), new Point(car.X + 2, this.Height - 4));
            }
        }
    }
}